package com.scs.application.core.configuration;

import cn.afterturn.easypoi.exception.excel.ExcelImportException;
import com.alibaba.fastjson.JSONException;
import com.scs.application.consts.ErrorCodes;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.model.CommonResult;
import com.scs.application.core.mvc.filter.ContentCachingRequestWrapper;
import com.scs.application.core.utils.BeanValidators;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.nio.file.AccessDeniedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * controller 全局异常处理
 *
 */
@Slf4j
@Configuration
@RestControllerAdvice
public class ExceptionHandleConfiguration {
    private void _logError(String errorType,Exception ex,HttpServletRequest request) {
        log.error("##########{},产生时间{}",errorType, DateUtils.format(DateUtils.now(),DateUtils.DEFAULT_PATTER_ALL));
        log.error("异常信息",ex);
    }

    @ExceptionHandler(value = {Exception.class,Error.class})
    public ResponseEntity<CommonResult> commonExceptionHandle(Exception ex, HttpServletRequest request) {
        _logError("未知异常",ex,request);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(CommonResult.error(ErrorCodes.INTERNAL_SERVER_ERROR, "服务器异常,请联系运维人员", null));
    }


    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
    public ResponseEntity<CommonResult> httpMessageNotReadableExceptionHandle(HttpMessageNotReadableException ex,
                                                                              ContentCachingRequestWrapper request) {
        if (ex.getMessage().indexOf("JSON parse error: Invalid UTF-8 middle byte") != -1) {
            try {
                byte[] bytes = request.getBody();
                log.error("请求的数据：\n" + new String(bytes, "UTF-8"), ex);

            } catch (IOException e) {
                e.printStackTrace();
            }
            return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, "请求的数据中可能包含乱码信息", null));
        }
        _logError("请求异常-数据接收异常",ex,request);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(CommonResult.error(ErrorCodes.INTERNAL_SERVER_ERROR, "服务器异常,请联系运维人员", null));
    }

//    @ConditionalOnClass(BadSqlGrammarException.class)
//    @ExceptionHandler(value = {BadSqlGrammarException.class})
//    public ResponseEntity<CommonResult> badSqlGrammarExceptionHandle(BadSqlGrammarException ex, HttpServletRequest request) {
//        log.error("sql parse error , the sql is " + ex.getSql(), ex);
//        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(CommonResult.error(ErrorCodes.INTERNAL_SERVER_ERROR, "SQL解析失败，详细信息请查看后台日志", null));
//    }
//    @ConditionalOnClass(OAuth2Exception.class)
//    @ExceptionHandler(value = {OAuth2Exception.class})
//    public ResponseEntity<CommonResult> oauth2ExceptionHandle(OAuth2Exception ex, HttpServletRequest request) {
//        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(CommonResult.error(ErrorCodes.INTERNAL_SERVER_ERROR, ex.getMessage(), null));
//    }

    @ConditionalOnClass(NumberFormatException.class)
    @ExceptionHandler(value = {NumberFormatException.class})
    public ResponseEntity<CommonResult> numberFormatExceptionHandle(NumberFormatException ex, HttpServletRequest request) {
        _logError("请求异常-数字格式化异常",ex,request);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(CommonResult.error(ErrorCodes.INTERNAL_SERVER_ERROR, "数字格式化异常", null));
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    public ResponseEntity<CommonResult> httpRequestMethodNotSupportedExceptionHandle(HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
        _logError("请求异常-方法不支持异常",ex,request);
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, "请求方法：" + request.getMethod() + "不支持", null));
    }

    @ExceptionHandler(value = {HttpClientErrorException.BadRequest.class})
    public ResponseEntity<CommonResult> badRequestExceptionHandle(HttpClientErrorException.BadRequest ex) {
        _logError("请求异常-访问令牌无效",ex,null);
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, "访问令牌无效，请重新登录", null));
    }

    @ExceptionHandler(value = {IllegalStateException.class})
    public ResponseEntity<CommonResult> illegalStateExceptionHandle(IllegalStateException ex) {
        String instanceName = StringUtils.substringAfterLast(ex.getMessage(), "for");
        log.error("服务" + instanceName + "未启动或服务注册列表未更新为最新状态", ex);
        _logError("请求异常-服务"+instanceName+"不可用",ex,null);
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, "服务暂不可用，请等待", null));
    }

    @ExceptionHandler(value = {BusinessException.class})
    public ResponseEntity<CommonResult> businessExceptionHandle(BusinessException ex) {
        _logError("业务异常",ex,null);
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, ex.getMessage(), null));
    }


    @ExceptionHandler(value = {ExcelImportException.class})
    public ResponseEntity<CommonResult> ExcelImportExceptionHandle(ExcelImportException ex) {
        _logError("数据导入异常",ex,null);
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, ex.getMessage(), null));
    }

    @ExceptionHandler(value = {JSONException.class})
    public ResponseEntity<CommonResult> jsonExceptionHandle(JSONException ex) {
        _logError("请求异常-参数格式错误",ex,null);
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, "参数错误", null));
    }

    @ConditionalOnClass(AccessDeniedException.class)
    @ExceptionHandler(value = {AccessDeniedException.class})
    public ResponseEntity<CommonResult> accessDeniedExceptionnHandle(AccessDeniedException ex) {
        _logError("请求异常-访问拒绝",ex,null);
        return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CommonResult.error(ErrorCodes.FORBIDDEN_ERROR, "权限不足，禁止访问", null));
    }

    @ExceptionHandler(value = {ConstraintViolationException.class})
    public ResponseEntity<CommonResult> validationExceptionHandle(ConstraintViolationException ex) {
        _logError("请求异常-违反约束异常",ex,null);
        String message = StringUtils.join(BeanValidators.extractPropertyAndMessageAsList(ex).toArray(), ";");
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.VALIDATION_ERROR, message, null));
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class})
    public ResponseEntity<CommonResult> validationExceptionHandle(Exception ex) {
        List<ObjectError> allErrors = Collections.emptyList();
        if (ex instanceof MethodArgumentNotValidException) {
            allErrors = ((MethodArgumentNotValidException) ex).getBindingResult().getAllErrors();
        } else if (ex instanceof BindException) {
            allErrors = ((BindException) ex).getBindingResult().getAllErrors();
        }

        List<String> errorMessages = new ArrayList<>(allErrors.size());
        for (ObjectError error : allErrors) {
            errorMessages.add(error.getDefaultMessage());
        }
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.VALIDATION_ERROR, StringUtils.join(errorMessages, ","), null));
    }

    @ExceptionHandler(value = {IllegalArgumentException.class})
    public ResponseEntity<CommonResult> illegalArgumentExceptionHandle(IllegalArgumentException ex) {
        return ResponseEntity.status(HttpStatus.OK).body(CommonResult.error(ErrorCodes.COMMON_ERROR, ex.getMessage(), null));
    }
}
